package com.senlingspace.web.controller.weixin;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.github.pagehelper.PageInfo;
import com.senlingspace.common.constant.HttpStatus;
import com.senlingspace.common.core.domain.AjaxResult;
import com.senlingspace.common.core.page.TableDataInfo;
import com.senlingspace.common.core.redis.RedisLock;
import com.senlingspace.common.enums.GoodsStatusEnum;
import com.senlingspace.common.request.OrderRequest;
import com.senlingspace.common.request.PrepaymentRequest;
import com.senlingspace.common.utils.StringUtils;
import com.senlingspace.framework.security.context.SecurityUtilExt;
import com.senlingspace.framework.support.WeChatMiniAppPageSupport;
import com.senlingspace.payment.core.ConcreteOrderProcess;
import com.senlingspace.payment.core.refund.IRefundService;
import com.senlingspace.system.domain.SlkjOrder;
import com.senlingspace.system.domain.vo.MiniAppOrderDetailVo;
import com.senlingspace.system.domain.vo.MiniAppOrderVo;
import com.senlingspace.system.domain.vo.OrderAddressVo;
import com.senlingspace.system.service.ISlkjOrderService;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.springframework.util.DigestUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;
import javax.validation.constraints.Pattern;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.Objects;
import java.util.concurrent.TimeUnit;

/**
 * 微信小程序订单
 *
 * @author lebronjames
 * @date 2024/09/24
 */
@Slf4j
@Validated
@AllArgsConstructor
@RestController
@RequestMapping(path = "/wmp/order/v1")
public class MiniAppOrderController {

    private final RedisLock redisLock;
    private final ConcreteOrderProcess concreteOrderProcess;
    private final ISlkjOrderService iSlkjOrderService;
    private final IRefundService iRefundService;

    /**
     * 创建订单（票类订单）
     *
     * @param orderRequest 订单请求
     * @return {@link AjaxResult }
     */
    @PostMapping(path = "/create")
    public AjaxResult createOrder(@Valid @RequestBody OrderRequest orderRequest) {
        log.info("微信小程序创建票类订单，入参：{}", JSON.toJSONString(orderRequest));

        orderRequest.setShopId(SecurityUtilExt.getShopId());
        String reqHash = DigestUtils.md5DigestAsHex(orderRequest.toString().getBytes(StandardCharsets.UTF_8));
        String lockKey = "WX_TICKET_ORDER_LOCK:" + reqHash;
        RLock lock = redisLock.getRLock(lockKey);

        boolean isLocked = false;
        try {
            isLocked = lock.tryLock(15, TimeUnit.SECONDS);
            if (isLocked) {
                return concreteOrderProcess.processOrderWeChat(orderRequest, SecurityUtilExt.getMobile(), SecurityUtilExt.getCustomerId());
            } else {
                log.warn("用户重复提交！锁超时：{}", lockKey);
                return AjaxResult.error("请勿重复下单！");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("微信小程序提交订单请求时发生异常：{}", e.getMessage(), e);
            return AjaxResult.error("下单失败，请刷新重试！");
        } finally {
            if (isLocked && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }


    /**
     * 预下单
     *
     * @param req
     * @return {@link AjaxResult }
     */
    @PostMapping(path = "/prepayment")
    public AjaxResult prepayment(@Valid @RequestBody PrepaymentRequest req) {
        log.info("微信小程序预下单请求参数：{}", JSON.toJSONString(req));
        String lockKey = "WX_PAYMENT_LOCK:" + req.getOrderId();
        RLock lock = redisLock.getRLock(lockKey);
        boolean isLocked = false;
        try {
            isLocked = lock.tryLock(15, TimeUnit.SECONDS);
            if (isLocked) {
                return concreteOrderProcess.processWxPrepayment(req, SecurityUtilExt.getMobile());
            } else {
                log.warn("用户重复提交！锁超时：{}", lockKey);
                return AjaxResult.error("请勿重复下单！");
            }
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("处理预支付请求时发生异常：{}", e.getMessage(), e);
            return AjaxResult.error("下单失败！");
        } finally {
            if (isLocked && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 小程序退款
     *
     * @param request
     * @return {@link AjaxResult }
     */
    @PostMapping(path = "/refund")
    public AjaxResult refundOrder(@RequestBody JSONObject request) {
        log.info("小程序退款，入参：{}", request);
        if (Objects.isNull(request)) {
            return AjaxResult.error("订单ID不能为空！");
        }

        SlkjOrder order = iSlkjOrderService.selectSlkjOrderByOrderId(request.getLong("orderId"));
        if (Objects.isNull(order)) {
            return AjaxResult.error("订单不存在！");
        }

        String goodsStatus = order.getGoodsStatus();
        if (StringUtils.isNoneBlank(goodsStatus) && Arrays.asList(GoodsStatusEnum.SHIPPED.name(), GoodsStatusEnum.COMPLETED.name()).contains(goodsStatus)) {
            return AjaxResult.error("订单已发货，无法退款！");
        }

        String lockKey = "WX_REFUND_LOCK:" + request.getString("orderId");
        RLock lock = redisLock.getRLock(lockKey);

        boolean isLocked = false;
        try {
            isLocked = lock.tryLock(15, TimeUnit.SECONDS);
            if (isLocked) {
                return iRefundService.refundOrder(request.getString("orderId"), Long.parseLong(SecurityUtilExt.getMobile()));
            }
            log.warn("用户重复提交！锁超时：{}", lockKey);
            return AjaxResult.error("请勿重复退款！");
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("处理退款请求时发生异常：{}", e.getMessage(), e);
            return AjaxResult.error("退款失败，请刷新重试！");
        } finally {
            if (isLocked && lock.isHeldByCurrentThread()) {
                lock.unlock();
            }
        }
    }

    /**
     * 订单列表
     *
     * @param type 订单类型：ticket/goods
     * @return {@link TableDataInfo }
     */
    @GetMapping(path = "/orders/{type}")
    public TableDataInfo orderList(@PathVariable @Pattern(regexp = "ticket|goods", message = "无效的订单类型！") String type) {
        log.info("微信小程序订单列表：type={}", type);
        PageInfo<MiniAppOrderVo> pageInfo = iSlkjOrderService.miniAppOrderList(type,
                SecurityUtilExt.getCustomerId(), SecurityUtilExt.getShopId(),
                WeChatMiniAppPageSupport.getPageNum(), WeChatMiniAppPageSupport.getPageSize());

        TableDataInfo result = new TableDataInfo(pageInfo.getTotal(), pageInfo.getList(), HttpStatus.SUCCESS, "success");
        log.info("用户 [{}] 微信小程序订单列表：{}", SecurityUtilExt.getMobile(), JSON.toJSONString(result));
        return result;
    }

    /**
     * 订单详情
     *
     * @param orderId
     * @return {@link AjaxResult }
     */
    @GetMapping(path = "/orderDetail/{orderId}")
    public AjaxResult orderDetail(@PathVariable Long orderId) {
        log.info("微信小程序订单详情：orderId={}", orderId);
        MiniAppOrderDetailVo orderDetail = iSlkjOrderService.miniAppOrderDetail(orderId);
        return AjaxResult.success(orderDetail);
    }

    /**
     * 修改订单地址
     *
     * @param request {订单ID，收获地址}
     * @return {@link AjaxResult }
     */
    @PutMapping(path = "/updateAddress")
    public AjaxResult updateAddress(@Valid @RequestBody OrderAddressVo request) {
        log.info("微信小程序订单修改地址：{}", JSON.toJSONString(request));
        return iSlkjOrderService.updateAddress(request, SecurityUtilExt.getCustomerId(), SecurityUtilExt.getShopId());
    }

}
